#include "HexBin.h"


char HexBin::HEX_NUMBER_TABLE[HexBin::BASE_LENGTH];
char HexBin::UPPER_CHARS[HexBin::LOOKUP_LENGTH];
char HexBin::LOWER_CHARS[HexBin::LOOKUP_LENGTH];

bool HexBin::__init = HexBin::init();
bool HexBin::init()
{
  for (int i = 0; i < BASE_LENGTH; i++)
  {
    HEX_NUMBER_TABLE[i] = -1;
  }
  for (int i = '9'; i >= '0'; i--)
  {
    HEX_NUMBER_TABLE[i] = (char)(i - '0');
  }
  for (int i = 'F'; i >= 'A'; i--)
  {
    HEX_NUMBER_TABLE[i] = (char)(i - 'A' + 10);
  }
  for (int i = 'f'; i >= 'a'; i--)
  {
    HEX_NUMBER_TABLE[i] = (char)(i - 'a' + 10);
  }

  for (int i = 0; i < 10; i++)
  {
    UPPER_CHARS[i] = (char)('0' + i);
    LOWER_CHARS[i] = (char)('0' + i);
  }
  for (int i = 10; i <= 15; i++)
  {
    UPPER_CHARS[i] = (char)('A' + i - 10);
    LOWER_CHARS[i] = (char)('a' + i - 10);
  }
}

std::string HexBin::encode(char *bytes)
{
  return encode(bytes, true);
}

std::string HexBin::encode(char *bytes, bool upperCase)
{
  if (bytes == nullptr)
  {
    return nullptr;
  }

  char *chars = upperCase ? UPPER_CHARS : LOWER_CHARS;

  char hex[sizeof(bytes) * 2];
  for (int i = 0; i < sizeof(bytes); i++)
  {
    int b = bytes[i] & 0xFF;
    hex[i * 2] = chars[b >> 4];
    hex[i * 2 + 1] = chars[b & 0xf];
  }
  return hex;
}

/**
 * Decode hex string to a char array
 *
 * @param encoded encoded string
 * @return return array of char to encode
 */
const char *HexBin::decode(std::string encoded)
{
  // if (encoded == nullptr) {
  //     return nullptr;
  // }

  int lengthData = encoded.length();
  if (lengthData % 2 != 0)
  {
    return nullptr;
  }

  const char *binaryData = encoded.c_str();
  int lengthDecode = lengthData / 2;
  char decodedData[lengthDecode];
  char temp1, temp2;
  char tempChar;
  for (int i = 0; i < lengthDecode; i++)
  {
    tempChar = binaryData[i * 2];
    temp1 = (tempChar < BASE_LENGTH) ? HEX_NUMBER_TABLE[tempChar] : -1;
    if (temp1 == -1)
    {
      return nullptr;
    }
    tempChar = binaryData[i * 2 + 1];
    temp2 = (tempChar < BASE_LENGTH) ? HEX_NUMBER_TABLE[tempChar] : -1;
    if (temp2 == -1)
    {
      return nullptr;
    }
    decodedData[i] = (char)((temp1 << 4) | temp2);
  }
  std::string tmp = decodedData;
  return tmp.c_str();
}
